/*
 * Copyright (c) 2016. Axon Framework
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.imooc.example.order;

import com.imooc.example.order.command.StudentFailCommand;
import com.imooc.example.order.command.StudentFinishCommand;
import com.imooc.example.order.event.StudentFailedEvent;
import com.imooc.example.order.event.saga.StudentAskFaildEvent;
import com.imooc.example.order.event.saga.StudentCreatedEvent;
import com.imooc.example.ticket.command.StudentAgeCommand;
import com.imooc.example.ticket.event.saga.StudentAgedEvent;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.callbacks.LoggingCallback;
import org.axonframework.eventhandling.saga.EndSaga;
import org.axonframework.eventhandling.saga.SagaEventHandler;
import org.axonframework.eventhandling.saga.StartSaga;
import org.axonframework.eventhandling.scheduling.EventScheduler;
import org.axonframework.eventhandling.scheduling.ScheduleToken;
import org.axonframework.spring.stereotype.Saga;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Instant;

import static org.axonframework.commandhandling.GenericCommandMessage.asCommandMessage;

@Slf4j
@Saga
public class StudentManagementSaga {

    private static final Logger LOG = LoggerFactory.getLogger(StudentManagementSaga.class);

    @Autowired
    private transient CommandBus commandBus;
    @Autowired
    private transient EventScheduler eventScheduler;

    private String ageId;
    private String studentId;
    private String name;
    private Integer age;

    private ScheduleToken timeoutToken;

    @StartSaga
    @SagaEventHandler(associationProperty = "studentId")
    public void on(StudentCreatedEvent event) {
        this.studentId = event.getStudentId();
        this.name = event.getName();

        StudentAgeCommand command = StudentAgeCommand.builder()
                .ageId(studentId)
                .studentId(studentId)
                .name(name)
                .age(18)
                .build();

        timeoutToken = eventScheduler.schedule(Instant.now().plusSeconds(5),
                StudentAskFaildEvent.builder().studentId(studentId).build());

        log.info("timeoutToken {}", timeoutToken);
        log.info("发送询问年龄command {}", command);

        commandBus.dispatch(asCommandMessage(command), LoggingCallback.INSTANCE);
    }

    @SagaEventHandler(associationProperty = "studentId")
    @EndSaga
    public void onAge(StudentAgedEvent event) {
        this.studentId = event.getStudentId();
        this.age = event.getAge();

        StudentFinishCommand command = StudentFinishCommand.builder()
                .studentId(studentId)
                .name(name)
                .age(age)
                .build();

        log.info("询问结束 {}", command);

        if (this.timeoutToken != null) {
            eventScheduler.cancelSchedule(this.timeoutToken);
        }

        commandBus.dispatch(asCommandMessage(command), LoggingCallback.INSTANCE);
    }

    @SagaEventHandler(associationProperty = "studentId")
    @EndSaga
    public void onFail(StudentAskFaildEvent event) {
        LOG.info("Student询问失败:{} failed.", event.getStudentId());
        StudentFailCommand finishCommand =
                StudentFailCommand.builder()
                        .studentId(event.getStudentId())
                        .reason("询问超时").build();
        commandBus.dispatch(asCommandMessage(finishCommand), LoggingCallback.INSTANCE);
    }
}
